{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import time\n",
    "from collections import defaultdict\n",
    "import scipy.sparse as ss\n",
    "#python SQLITE数据库是一款非常小巧的\n",
    "import scipy.sparse as ss\n",
    "import scipy.io as sio\n",
    "import scipy.spatial.distance as ssd\n",
    "import pickle as pk\n",
    "\n",
    "from numpy.random import random\n",
    "import sqlite3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>user</th>\n",
       "      <th>song</th>\n",
       "      <th>play_count</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOCKSGZ12A58A7CA4B</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOCVTLJ12A6310F0FD</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SODLLYS12A8C13A96B</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOEGIYH12A6D4FC0E3</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOFRQTD12A81C233C0</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                       user                song  play_count\n",
       "0  4e11f45d732f4861772b2906f81a7d384552ad12  SOCKSGZ12A58A7CA4B           1\n",
       "1  4e11f45d732f4861772b2906f81a7d384552ad12  SOCVTLJ12A6310F0FD           1\n",
       "2  4e11f45d732f4861772b2906f81a7d384552ad12  SODLLYS12A8C13A96B           3\n",
       "3  4e11f45d732f4861772b2906f81a7d384552ad12  SOEGIYH12A6D4FC0E3           1\n",
       "4  4e11f45d732f4861772b2906f81a7d384552ad12  SOFRQTD12A81C233C0           2"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dpath=\"E:\\\\csdn\\\\data\\\\Data\\\\\"\n",
    "df_triplet = pd.read_csv(filepath_or_buffer =dpath + 'triplet_dataset_sub.csv' )#,names=['user','song','play_count'])\n",
    "df_triplet.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<module 'sys' (built-in)>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import sys\n",
    "import importlib\n",
    "importlib.reload(sys)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "#df_triplet_users=df_triplet[['user','play_count']].groupby('user').sum()\n",
    "df_triplet_users=df_triplet[['user','play_count']].groupby('user').sum().reset_index() #groupby是按照某个属性来\n",
    "#处理数据，reset_index是加上序号\n",
    "df_triplet_users.rename(columns={\"play_count\":\"total_play_count\"},inplace=True) #换个名字"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>user</th>\n",
       "      <th>total_play_count</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0025bfe6248070545d23721083acd3f60451da4f</td>\n",
       "      <td>52</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>002b63a7e2247de6d62bc62f253474edc7dd044c</td>\n",
       "      <td>686</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>003a5e3285141b1a54edbc51fbfa1cc922023aae</td>\n",
       "      <td>655</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0084ecc8a2b3b0a371b968ded8b92d3d8525fd64</td>\n",
       "      <td>33</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0091e0326c4c034cc04be6454742912845740a1f</td>\n",
       "      <td>230</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>00a55d1ba6f63109c208dbd80570520d5d80f563</td>\n",
       "      <td>29</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>00d7dede8a10a03ea0b2d4a08449a9776d414923</td>\n",
       "      <td>178</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>00fa0c8162aa95341f4da9defede8aae0675d3cc</td>\n",
       "      <td>600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>010a2a11d5013b81195a4b2c5b4ef8996a60f4a9</td>\n",
       "      <td>32</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>01a957fd771b0e80ef7843684217cad5939b4add</td>\n",
       "      <td>212</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>02471b044e6bdff7c01e1ea2791214268ba5aaf4</td>\n",
       "      <td>362</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>0252acdea2a493da2704c23eebaeaa155b18b7d0</td>\n",
       "      <td>933</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>0298a31b3535c3a3f972bc0d342cfc207c3cd8a6</td>\n",
       "      <td>248</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>03699fa50d944261dd0fe6eb6c4b58cbb44bdae5</td>\n",
       "      <td>13</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>04043d5716a2359f49f62d13c7c3d3e72b28f520</td>\n",
       "      <td>212</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>0421d096b0c80ec287d436e6f535f44b711b58ef</td>\n",
       "      <td>1017</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>16</th>\n",
       "      <td>0469bfcd3e17b383cbf1a362af8844a44339998d</td>\n",
       "      <td>671</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>17</th>\n",
       "      <td>04ba112cdf196358a56d6bdbf453bb0b2eb50b1c</td>\n",
       "      <td>1468</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>18</th>\n",
       "      <td>05be6a588cc454d1e400a358c562807aeec8c054</td>\n",
       "      <td>223</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19</th>\n",
       "      <td>0618bf6227486c545a548a649d32cee247dd198d</td>\n",
       "      <td>269</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>20</th>\n",
       "      <td>062eef2a03b53d2b10f5018135e3361659c6a3bf</td>\n",
       "      <td>208</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>21</th>\n",
       "      <td>074a2197ff72db9f7e44606dfd33208dcdf29f06</td>\n",
       "      <td>70</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>22</th>\n",
       "      <td>083a2a59603a605275107c00812a811526c2a0af</td>\n",
       "      <td>1081</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>23</th>\n",
       "      <td>093cb74eb3c517c5179ae24caf0ebec51b24d2a2</td>\n",
       "      <td>296</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>24</th>\n",
       "      <td>0a4c3c6999c74af7d8a44e96b44bf64e513c0f8b</td>\n",
       "      <td>643</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25</th>\n",
       "      <td>0a66acea5854a05a1514cd259124433b4190534a</td>\n",
       "      <td>97</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>26</th>\n",
       "      <td>0aae6978a0342cf0c356aa8a28ec6516df684025</td>\n",
       "      <td>311</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>27</th>\n",
       "      <td>0ab9d9f7925520801fffa8b63287d799cfe9a5a4</td>\n",
       "      <td>400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>28</th>\n",
       "      <td>0ad0283d63a5c591a104142f8a2f5bbd779389b0</td>\n",
       "      <td>98</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>29</th>\n",
       "      <td>0adc1da3be9d2c9fa26d21268713fe4030402781</td>\n",
       "      <td>232</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>760</th>\n",
       "      <td>f6ae5e682750e815c1709ca99138d03b039839d6</td>\n",
       "      <td>1508</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>761</th>\n",
       "      <td>f6d78516f331c684ee611e07effcb796e94ae456</td>\n",
       "      <td>666</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>762</th>\n",
       "      <td>f799c4ea9030eea12c078db1c1fcd5fa956e786b</td>\n",
       "      <td>561</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>763</th>\n",
       "      <td>f8181f9b3d85fa4ac04c66bc9f84f0ad2a18a777</td>\n",
       "      <td>787</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>764</th>\n",
       "      <td>f84fb3d29bb05bb9dec96684215c763ccbbc67a9</td>\n",
       "      <td>572</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>765</th>\n",
       "      <td>f8544ba8ff908f44d61f5d9d17c213423c1fc782</td>\n",
       "      <td>15</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>766</th>\n",
       "      <td>f986a1b01b2a75109baa39d637537b5124c111ab</td>\n",
       "      <td>48</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>767</th>\n",
       "      <td>f99a25251dfd3c44b629c3658bf6c0d0a7a3d0ce</td>\n",
       "      <td>709</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>768</th>\n",
       "      <td>f9cf7849592621b46a793e0f283de8ab48b3d5f8</td>\n",
       "      <td>65</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>769</th>\n",
       "      <td>f9edc8907be695518817082a224aa43beca7d994</td>\n",
       "      <td>302</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>770</th>\n",
       "      <td>fa5d9eddc010bc3fc71f8a42db15e5dd4f1c18a3</td>\n",
       "      <td>832</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>771</th>\n",
       "      <td>faf0beb5d7ff9d39244b0713de08304c3691f71b</td>\n",
       "      <td>401</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>772</th>\n",
       "      <td>fb644c3f2a83114325dc67b97df0bce60b5ac9a1</td>\n",
       "      <td>641</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>773</th>\n",
       "      <td>fba8ff1f9dd32aa35f3e13960a008fec773e2903</td>\n",
       "      <td>350</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>774</th>\n",
       "      <td>fbd1b7d1bf19158773820cb45639362347979926</td>\n",
       "      <td>529</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>775</th>\n",
       "      <td>fc05f377863a77d7784b02de2cc06cdecb85968b</td>\n",
       "      <td>239</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>776</th>\n",
       "      <td>fc77d71ecc8a4c7f4a0402fbe9118973124391fe</td>\n",
       "      <td>387</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>777</th>\n",
       "      <td>fcbc6bdcec1f293d1d03bbf3c64f613e59acbfe0</td>\n",
       "      <td>726</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>778</th>\n",
       "      <td>fd1ebc6caa7ad07c84677ba6bada683077bf0f15</td>\n",
       "      <td>304</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>779</th>\n",
       "      <td>fe2d77de7e57f3b3eedcf473545110b13ca03426</td>\n",
       "      <td>919</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>780</th>\n",
       "      <td>fe53f4bc06e09b02015312e1d0ea48b208cd490e</td>\n",
       "      <td>278</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>781</th>\n",
       "      <td>fe67eae6791418a5a85125145609f518f01efe48</td>\n",
       "      <td>393</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>782</th>\n",
       "      <td>fe8b98246d279f71f7cb0d493cdedce2bbc30aae</td>\n",
       "      <td>378</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>783</th>\n",
       "      <td>fe9a05c03c29da973743a83b80d1660748077432</td>\n",
       "      <td>109</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>784</th>\n",
       "      <td>fef771ab021c200187a419f5e55311390f850a50</td>\n",
       "      <td>186</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>785</th>\n",
       "      <td>ff124a0cd09e26b78b2b7d3a1de83512ba9978c8</td>\n",
       "      <td>383</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>786</th>\n",
       "      <td>ff7429bd2788349b026cf8f8a7a4b3f3971a310a</td>\n",
       "      <td>303</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>787</th>\n",
       "      <td>ffa96cd6cc641b38a946e8444d261435d615b2dc</td>\n",
       "      <td>87</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>788</th>\n",
       "      <td>ffe2ec5b72cddb8537ad7f0ac191624f8ae2c8dc</td>\n",
       "      <td>16</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>789</th>\n",
       "      <td>ffe5ad43c24d81878621185e164043a6e49b2fe4</td>\n",
       "      <td>422</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>790 rows × 2 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "                                         user  total_play_count\n",
       "0    0025bfe6248070545d23721083acd3f60451da4f                52\n",
       "1    002b63a7e2247de6d62bc62f253474edc7dd044c               686\n",
       "2    003a5e3285141b1a54edbc51fbfa1cc922023aae               655\n",
       "3    0084ecc8a2b3b0a371b968ded8b92d3d8525fd64                33\n",
       "4    0091e0326c4c034cc04be6454742912845740a1f               230\n",
       "5    00a55d1ba6f63109c208dbd80570520d5d80f563                29\n",
       "6    00d7dede8a10a03ea0b2d4a08449a9776d414923               178\n",
       "7    00fa0c8162aa95341f4da9defede8aae0675d3cc               600\n",
       "8    010a2a11d5013b81195a4b2c5b4ef8996a60f4a9                32\n",
       "9    01a957fd771b0e80ef7843684217cad5939b4add               212\n",
       "10   02471b044e6bdff7c01e1ea2791214268ba5aaf4               362\n",
       "11   0252acdea2a493da2704c23eebaeaa155b18b7d0               933\n",
       "12   0298a31b3535c3a3f972bc0d342cfc207c3cd8a6               248\n",
       "13   03699fa50d944261dd0fe6eb6c4b58cbb44bdae5                13\n",
       "14   04043d5716a2359f49f62d13c7c3d3e72b28f520               212\n",
       "15   0421d096b0c80ec287d436e6f535f44b711b58ef              1017\n",
       "16   0469bfcd3e17b383cbf1a362af8844a44339998d               671\n",
       "17   04ba112cdf196358a56d6bdbf453bb0b2eb50b1c              1468\n",
       "18   05be6a588cc454d1e400a358c562807aeec8c054               223\n",
       "19   0618bf6227486c545a548a649d32cee247dd198d               269\n",
       "20   062eef2a03b53d2b10f5018135e3361659c6a3bf               208\n",
       "21   074a2197ff72db9f7e44606dfd33208dcdf29f06                70\n",
       "22   083a2a59603a605275107c00812a811526c2a0af              1081\n",
       "23   093cb74eb3c517c5179ae24caf0ebec51b24d2a2               296\n",
       "24   0a4c3c6999c74af7d8a44e96b44bf64e513c0f8b               643\n",
       "25   0a66acea5854a05a1514cd259124433b4190534a                97\n",
       "26   0aae6978a0342cf0c356aa8a28ec6516df684025               311\n",
       "27   0ab9d9f7925520801fffa8b63287d799cfe9a5a4               400\n",
       "28   0ad0283d63a5c591a104142f8a2f5bbd779389b0                98\n",
       "29   0adc1da3be9d2c9fa26d21268713fe4030402781               232\n",
       "..                                        ...               ...\n",
       "760  f6ae5e682750e815c1709ca99138d03b039839d6              1508\n",
       "761  f6d78516f331c684ee611e07effcb796e94ae456               666\n",
       "762  f799c4ea9030eea12c078db1c1fcd5fa956e786b               561\n",
       "763  f8181f9b3d85fa4ac04c66bc9f84f0ad2a18a777               787\n",
       "764  f84fb3d29bb05bb9dec96684215c763ccbbc67a9               572\n",
       "765  f8544ba8ff908f44d61f5d9d17c213423c1fc782                15\n",
       "766  f986a1b01b2a75109baa39d637537b5124c111ab                48\n",
       "767  f99a25251dfd3c44b629c3658bf6c0d0a7a3d0ce               709\n",
       "768  f9cf7849592621b46a793e0f283de8ab48b3d5f8                65\n",
       "769  f9edc8907be695518817082a224aa43beca7d994               302\n",
       "770  fa5d9eddc010bc3fc71f8a42db15e5dd4f1c18a3               832\n",
       "771  faf0beb5d7ff9d39244b0713de08304c3691f71b               401\n",
       "772  fb644c3f2a83114325dc67b97df0bce60b5ac9a1               641\n",
       "773  fba8ff1f9dd32aa35f3e13960a008fec773e2903               350\n",
       "774  fbd1b7d1bf19158773820cb45639362347979926               529\n",
       "775  fc05f377863a77d7784b02de2cc06cdecb85968b               239\n",
       "776  fc77d71ecc8a4c7f4a0402fbe9118973124391fe               387\n",
       "777  fcbc6bdcec1f293d1d03bbf3c64f613e59acbfe0               726\n",
       "778  fd1ebc6caa7ad07c84677ba6bada683077bf0f15               304\n",
       "779  fe2d77de7e57f3b3eedcf473545110b13ca03426               919\n",
       "780  fe53f4bc06e09b02015312e1d0ea48b208cd490e               278\n",
       "781  fe67eae6791418a5a85125145609f518f01efe48               393\n",
       "782  fe8b98246d279f71f7cb0d493cdedce2bbc30aae               378\n",
       "783  fe9a05c03c29da973743a83b80d1660748077432               109\n",
       "784  fef771ab021c200187a419f5e55311390f850a50               186\n",
       "785  ff124a0cd09e26b78b2b7d3a1de83512ba9978c8               383\n",
       "786  ff7429bd2788349b026cf8f8a7a4b3f3971a310a               303\n",
       "787  ffa96cd6cc641b38a946e8444d261435d615b2dc                87\n",
       "788  ffe2ec5b72cddb8537ad7f0ac191624f8ae2c8dc                16\n",
       "789  ffe5ad43c24d81878621185e164043a6e49b2fe4               422\n",
       "\n",
       "[790 rows x 2 columns]"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df_triplet_users"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "df_triplet=pd.merge(df_triplet,df_triplet_users) #按照默认的键值合并\n",
    "df_triplet['fraction_play']=df_triplet['play_count']/df_triplet['total_play_count']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>user</th>\n",
       "      <th>song</th>\n",
       "      <th>play_count</th>\n",
       "      <th>total_play_count</th>\n",
       "      <th>fraction_play</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOCKSGZ12A58A7CA4B</td>\n",
       "      <td>1</td>\n",
       "      <td>259</td>\n",
       "      <td>0.003861</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOCVTLJ12A6310F0FD</td>\n",
       "      <td>1</td>\n",
       "      <td>259</td>\n",
       "      <td>0.003861</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SODLLYS12A8C13A96B</td>\n",
       "      <td>3</td>\n",
       "      <td>259</td>\n",
       "      <td>0.011583</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOEGIYH12A6D4FC0E3</td>\n",
       "      <td>1</td>\n",
       "      <td>259</td>\n",
       "      <td>0.003861</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOFRQTD12A81C233C0</td>\n",
       "      <td>2</td>\n",
       "      <td>259</td>\n",
       "      <td>0.007722</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOHEMBB12A6701E907</td>\n",
       "      <td>1</td>\n",
       "      <td>259</td>\n",
       "      <td>0.003861</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOHJOLH12A6310DFE5</td>\n",
       "      <td>1</td>\n",
       "      <td>259</td>\n",
       "      <td>0.003861</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOIZLKI12A6D4F7B61</td>\n",
       "      <td>1</td>\n",
       "      <td>259</td>\n",
       "      <td>0.003861</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOJGSIO12A8C141DBF</td>\n",
       "      <td>1</td>\n",
       "      <td>259</td>\n",
       "      <td>0.003861</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOKEYJQ12A6D4F6132</td>\n",
       "      <td>1</td>\n",
       "      <td>259</td>\n",
       "      <td>0.003861</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOKLRPJ12A8C13C3FE</td>\n",
       "      <td>1</td>\n",
       "      <td>259</td>\n",
       "      <td>0.003861</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOKNWRZ12A8C13BF62</td>\n",
       "      <td>2</td>\n",
       "      <td>259</td>\n",
       "      <td>0.007722</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOKXYUW12A8C140229</td>\n",
       "      <td>1</td>\n",
       "      <td>259</td>\n",
       "      <td>0.003861</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOLAUOW12A8C13A400</td>\n",
       "      <td>3</td>\n",
       "      <td>259</td>\n",
       "      <td>0.011583</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOLLDVS12AB0183835</td>\n",
       "      <td>6</td>\n",
       "      <td>259</td>\n",
       "      <td>0.023166</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOLOZRE12A8C133256</td>\n",
       "      <td>1</td>\n",
       "      <td>259</td>\n",
       "      <td>0.003861</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>16</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOLWRZI12A6D4FC4F0</td>\n",
       "      <td>1</td>\n",
       "      <td>259</td>\n",
       "      <td>0.003861</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>17</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOMDVSL12A6D4F7230</td>\n",
       "      <td>2</td>\n",
       "      <td>259</td>\n",
       "      <td>0.007722</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>18</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOMGIYR12AB0187973</td>\n",
       "      <td>1</td>\n",
       "      <td>259</td>\n",
       "      <td>0.003861</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOMNGMO12A6702187E</td>\n",
       "      <td>1</td>\n",
       "      <td>259</td>\n",
       "      <td>0.003861</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>20</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOMRYYN12A6310F0F3</td>\n",
       "      <td>1</td>\n",
       "      <td>259</td>\n",
       "      <td>0.003861</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>21</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SONDCOR12A8C13BA16</td>\n",
       "      <td>1</td>\n",
       "      <td>259</td>\n",
       "      <td>0.003861</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>22</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SONQBUB12A6D4F8ED0</td>\n",
       "      <td>3</td>\n",
       "      <td>259</td>\n",
       "      <td>0.011583</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>23</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SONYKOW12AB01849C9</td>\n",
       "      <td>2</td>\n",
       "      <td>259</td>\n",
       "      <td>0.007722</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>24</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOOALOT12A8C13ABD9</td>\n",
       "      <td>5</td>\n",
       "      <td>259</td>\n",
       "      <td>0.019305</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOOKGRB12A8C13CD66</td>\n",
       "      <td>4</td>\n",
       "      <td>259</td>\n",
       "      <td>0.015444</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>26</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOOSJIV12AF729E09E</td>\n",
       "      <td>5</td>\n",
       "      <td>259</td>\n",
       "      <td>0.019305</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>27</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOOZFCC12A58A7D783</td>\n",
       "      <td>1</td>\n",
       "      <td>259</td>\n",
       "      <td>0.003861</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>28</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOPBXPQ12AB01887E2</td>\n",
       "      <td>2</td>\n",
       "      <td>259</td>\n",
       "      <td>0.007722</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>29</th>\n",
       "      <td>4e11f45d732f4861772b2906f81a7d384552ad12</td>\n",
       "      <td>SOPCTBB12AF72A1B64</td>\n",
       "      <td>1</td>\n",
       "      <td>259</td>\n",
       "      <td>0.003861</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37489</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOVBJIV12A81C22366</td>\n",
       "      <td>2</td>\n",
       "      <td>191</td>\n",
       "      <td>0.010471</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37490</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOVCHUK12AB017F41F</td>\n",
       "      <td>1</td>\n",
       "      <td>191</td>\n",
       "      <td>0.005236</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37491</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOVDLZN12AB0185BEA</td>\n",
       "      <td>5</td>\n",
       "      <td>191</td>\n",
       "      <td>0.026178</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37492</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOVJJQI12A6D4F5910</td>\n",
       "      <td>1</td>\n",
       "      <td>191</td>\n",
       "      <td>0.005236</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37493</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOVJTTZ12AB017F48F</td>\n",
       "      <td>5</td>\n",
       "      <td>191</td>\n",
       "      <td>0.026178</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37494</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOVMSAW12A6D4F95A4</td>\n",
       "      <td>2</td>\n",
       "      <td>191</td>\n",
       "      <td>0.010471</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37495</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOVRTPN12AB0184F9E</td>\n",
       "      <td>4</td>\n",
       "      <td>191</td>\n",
       "      <td>0.020942</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37496</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOVRZIX12AAF3B2A32</td>\n",
       "      <td>2</td>\n",
       "      <td>191</td>\n",
       "      <td>0.010471</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37497</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOVUBST12AB018C9A4</td>\n",
       "      <td>3</td>\n",
       "      <td>191</td>\n",
       "      <td>0.015707</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37498</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOWKKGX12A6D4FCC01</td>\n",
       "      <td>1</td>\n",
       "      <td>191</td>\n",
       "      <td>0.005236</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37499</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOWQJUV12A6701FA45</td>\n",
       "      <td>1</td>\n",
       "      <td>191</td>\n",
       "      <td>0.005236</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37500</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOWQOMG12A6701D1F3</td>\n",
       "      <td>1</td>\n",
       "      <td>191</td>\n",
       "      <td>0.005236</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37501</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOWSPUS12AC468BEE3</td>\n",
       "      <td>2</td>\n",
       "      <td>191</td>\n",
       "      <td>0.010471</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37502</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOWWCNJ12A81C1FFA5</td>\n",
       "      <td>2</td>\n",
       "      <td>191</td>\n",
       "      <td>0.010471</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37503</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOXGXKY12A8C13A405</td>\n",
       "      <td>10</td>\n",
       "      <td>191</td>\n",
       "      <td>0.052356</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37504</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOXHIDK12A58A7CFB3</td>\n",
       "      <td>1</td>\n",
       "      <td>191</td>\n",
       "      <td>0.005236</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37505</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOXIIIM12A6D4F66C8</td>\n",
       "      <td>1</td>\n",
       "      <td>191</td>\n",
       "      <td>0.005236</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37506</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOXILLO12A6310F1B6</td>\n",
       "      <td>1</td>\n",
       "      <td>191</td>\n",
       "      <td>0.005236</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37507</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOXLDLO12AB0186373</td>\n",
       "      <td>1</td>\n",
       "      <td>191</td>\n",
       "      <td>0.005236</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37508</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOXTYBL12AB01887BB</td>\n",
       "      <td>3</td>\n",
       "      <td>191</td>\n",
       "      <td>0.015707</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37509</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOXVVSM12A8C142224</td>\n",
       "      <td>1</td>\n",
       "      <td>191</td>\n",
       "      <td>0.005236</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37510</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOYCXUA12A8C133713</td>\n",
       "      <td>1</td>\n",
       "      <td>191</td>\n",
       "      <td>0.005236</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37511</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOYEVUY12A8C145F58</td>\n",
       "      <td>4</td>\n",
       "      <td>191</td>\n",
       "      <td>0.020942</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37512</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOYVSHP12A6702016E</td>\n",
       "      <td>2</td>\n",
       "      <td>191</td>\n",
       "      <td>0.010471</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37513</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOZCDWG12A6D4F81E1</td>\n",
       "      <td>1</td>\n",
       "      <td>191</td>\n",
       "      <td>0.005236</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37514</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOZEBLF12A6D4F8259</td>\n",
       "      <td>1</td>\n",
       "      <td>191</td>\n",
       "      <td>0.005236</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37515</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOZPPYS12898B694CE</td>\n",
       "      <td>3</td>\n",
       "      <td>191</td>\n",
       "      <td>0.015707</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37516</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOZVUCT12A8C1424BE</td>\n",
       "      <td>3</td>\n",
       "      <td>191</td>\n",
       "      <td>0.015707</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37517</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOZXEZV12A6D4F737F</td>\n",
       "      <td>1</td>\n",
       "      <td>191</td>\n",
       "      <td>0.005236</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37518</th>\n",
       "      <td>491d048e26c51fcda0744355bf191d4ccf36f118</td>\n",
       "      <td>SOZZIOH12A67ADE300</td>\n",
       "      <td>1</td>\n",
       "      <td>191</td>\n",
       "      <td>0.005236</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>37519 rows × 5 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "                                           user                song  \\\n",
       "0      4e11f45d732f4861772b2906f81a7d384552ad12  SOCKSGZ12A58A7CA4B   \n",
       "1      4e11f45d732f4861772b2906f81a7d384552ad12  SOCVTLJ12A6310F0FD   \n",
       "2      4e11f45d732f4861772b2906f81a7d384552ad12  SODLLYS12A8C13A96B   \n",
       "3      4e11f45d732f4861772b2906f81a7d384552ad12  SOEGIYH12A6D4FC0E3   \n",
       "4      4e11f45d732f4861772b2906f81a7d384552ad12  SOFRQTD12A81C233C0   \n",
       "5      4e11f45d732f4861772b2906f81a7d384552ad12  SOHEMBB12A6701E907   \n",
       "6      4e11f45d732f4861772b2906f81a7d384552ad12  SOHJOLH12A6310DFE5   \n",
       "7      4e11f45d732f4861772b2906f81a7d384552ad12  SOIZLKI12A6D4F7B61   \n",
       "8      4e11f45d732f4861772b2906f81a7d384552ad12  SOJGSIO12A8C141DBF   \n",
       "9      4e11f45d732f4861772b2906f81a7d384552ad12  SOKEYJQ12A6D4F6132   \n",
       "10     4e11f45d732f4861772b2906f81a7d384552ad12  SOKLRPJ12A8C13C3FE   \n",
       "11     4e11f45d732f4861772b2906f81a7d384552ad12  SOKNWRZ12A8C13BF62   \n",
       "12     4e11f45d732f4861772b2906f81a7d384552ad12  SOKXYUW12A8C140229   \n",
       "13     4e11f45d732f4861772b2906f81a7d384552ad12  SOLAUOW12A8C13A400   \n",
       "14     4e11f45d732f4861772b2906f81a7d384552ad12  SOLLDVS12AB0183835   \n",
       "15     4e11f45d732f4861772b2906f81a7d384552ad12  SOLOZRE12A8C133256   \n",
       "16     4e11f45d732f4861772b2906f81a7d384552ad12  SOLWRZI12A6D4FC4F0   \n",
       "17     4e11f45d732f4861772b2906f81a7d384552ad12  SOMDVSL12A6D4F7230   \n",
       "18     4e11f45d732f4861772b2906f81a7d384552ad12  SOMGIYR12AB0187973   \n",
       "19     4e11f45d732f4861772b2906f81a7d384552ad12  SOMNGMO12A6702187E   \n",
       "20     4e11f45d732f4861772b2906f81a7d384552ad12  SOMRYYN12A6310F0F3   \n",
       "21     4e11f45d732f4861772b2906f81a7d384552ad12  SONDCOR12A8C13BA16   \n",
       "22     4e11f45d732f4861772b2906f81a7d384552ad12  SONQBUB12A6D4F8ED0   \n",
       "23     4e11f45d732f4861772b2906f81a7d384552ad12  SONYKOW12AB01849C9   \n",
       "24     4e11f45d732f4861772b2906f81a7d384552ad12  SOOALOT12A8C13ABD9   \n",
       "25     4e11f45d732f4861772b2906f81a7d384552ad12  SOOKGRB12A8C13CD66   \n",
       "26     4e11f45d732f4861772b2906f81a7d384552ad12  SOOSJIV12AF729E09E   \n",
       "27     4e11f45d732f4861772b2906f81a7d384552ad12  SOOZFCC12A58A7D783   \n",
       "28     4e11f45d732f4861772b2906f81a7d384552ad12  SOPBXPQ12AB01887E2   \n",
       "29     4e11f45d732f4861772b2906f81a7d384552ad12  SOPCTBB12AF72A1B64   \n",
       "...                                         ...                 ...   \n",
       "37489  491d048e26c51fcda0744355bf191d4ccf36f118  SOVBJIV12A81C22366   \n",
       "37490  491d048e26c51fcda0744355bf191d4ccf36f118  SOVCHUK12AB017F41F   \n",
       "37491  491d048e26c51fcda0744355bf191d4ccf36f118  SOVDLZN12AB0185BEA   \n",
       "37492  491d048e26c51fcda0744355bf191d4ccf36f118  SOVJJQI12A6D4F5910   \n",
       "37493  491d048e26c51fcda0744355bf191d4ccf36f118  SOVJTTZ12AB017F48F   \n",
       "37494  491d048e26c51fcda0744355bf191d4ccf36f118  SOVMSAW12A6D4F95A4   \n",
       "37495  491d048e26c51fcda0744355bf191d4ccf36f118  SOVRTPN12AB0184F9E   \n",
       "37496  491d048e26c51fcda0744355bf191d4ccf36f118  SOVRZIX12AAF3B2A32   \n",
       "37497  491d048e26c51fcda0744355bf191d4ccf36f118  SOVUBST12AB018C9A4   \n",
       "37498  491d048e26c51fcda0744355bf191d4ccf36f118  SOWKKGX12A6D4FCC01   \n",
       "37499  491d048e26c51fcda0744355bf191d4ccf36f118  SOWQJUV12A6701FA45   \n",
       "37500  491d048e26c51fcda0744355bf191d4ccf36f118  SOWQOMG12A6701D1F3   \n",
       "37501  491d048e26c51fcda0744355bf191d4ccf36f118  SOWSPUS12AC468BEE3   \n",
       "37502  491d048e26c51fcda0744355bf191d4ccf36f118  SOWWCNJ12A81C1FFA5   \n",
       "37503  491d048e26c51fcda0744355bf191d4ccf36f118  SOXGXKY12A8C13A405   \n",
       "37504  491d048e26c51fcda0744355bf191d4ccf36f118  SOXHIDK12A58A7CFB3   \n",
       "37505  491d048e26c51fcda0744355bf191d4ccf36f118  SOXIIIM12A6D4F66C8   \n",
       "37506  491d048e26c51fcda0744355bf191d4ccf36f118  SOXILLO12A6310F1B6   \n",
       "37507  491d048e26c51fcda0744355bf191d4ccf36f118  SOXLDLO12AB0186373   \n",
       "37508  491d048e26c51fcda0744355bf191d4ccf36f118  SOXTYBL12AB01887BB   \n",
       "37509  491d048e26c51fcda0744355bf191d4ccf36f118  SOXVVSM12A8C142224   \n",
       "37510  491d048e26c51fcda0744355bf191d4ccf36f118  SOYCXUA12A8C133713   \n",
       "37511  491d048e26c51fcda0744355bf191d4ccf36f118  SOYEVUY12A8C145F58   \n",
       "37512  491d048e26c51fcda0744355bf191d4ccf36f118  SOYVSHP12A6702016E   \n",
       "37513  491d048e26c51fcda0744355bf191d4ccf36f118  SOZCDWG12A6D4F81E1   \n",
       "37514  491d048e26c51fcda0744355bf191d4ccf36f118  SOZEBLF12A6D4F8259   \n",
       "37515  491d048e26c51fcda0744355bf191d4ccf36f118  SOZPPYS12898B694CE   \n",
       "37516  491d048e26c51fcda0744355bf191d4ccf36f118  SOZVUCT12A8C1424BE   \n",
       "37517  491d048e26c51fcda0744355bf191d4ccf36f118  SOZXEZV12A6D4F737F   \n",
       "37518  491d048e26c51fcda0744355bf191d4ccf36f118  SOZZIOH12A67ADE300   \n",
       "\n",
       "       play_count  total_play_count  fraction_play  \n",
       "0               1               259       0.003861  \n",
       "1               1               259       0.003861  \n",
       "2               3               259       0.011583  \n",
       "3               1               259       0.003861  \n",
       "4               2               259       0.007722  \n",
       "5               1               259       0.003861  \n",
       "6               1               259       0.003861  \n",
       "7               1               259       0.003861  \n",
       "8               1               259       0.003861  \n",
       "9               1               259       0.003861  \n",
       "10              1               259       0.003861  \n",
       "11              2               259       0.007722  \n",
       "12              1               259       0.003861  \n",
       "13              3               259       0.011583  \n",
       "14              6               259       0.023166  \n",
       "15              1               259       0.003861  \n",
       "16              1               259       0.003861  \n",
       "17              2               259       0.007722  \n",
       "18              1               259       0.003861  \n",
       "19              1               259       0.003861  \n",
       "20              1               259       0.003861  \n",
       "21              1               259       0.003861  \n",
       "22              3               259       0.011583  \n",
       "23              2               259       0.007722  \n",
       "24              5               259       0.019305  \n",
       "25              4               259       0.015444  \n",
       "26              5               259       0.019305  \n",
       "27              1               259       0.003861  \n",
       "28              2               259       0.007722  \n",
       "29              1               259       0.003861  \n",
       "...           ...               ...            ...  \n",
       "37489           2               191       0.010471  \n",
       "37490           1               191       0.005236  \n",
       "37491           5               191       0.026178  \n",
       "37492           1               191       0.005236  \n",
       "37493           5               191       0.026178  \n",
       "37494           2               191       0.010471  \n",
       "37495           4               191       0.020942  \n",
       "37496           2               191       0.010471  \n",
       "37497           3               191       0.015707  \n",
       "37498           1               191       0.005236  \n",
       "37499           1               191       0.005236  \n",
       "37500           1               191       0.005236  \n",
       "37501           2               191       0.010471  \n",
       "37502           2               191       0.010471  \n",
       "37503          10               191       0.052356  \n",
       "37504           1               191       0.005236  \n",
       "37505           1               191       0.005236  \n",
       "37506           1               191       0.005236  \n",
       "37507           1               191       0.005236  \n",
       "37508           3               191       0.015707  \n",
       "37509           1               191       0.005236  \n",
       "37510           1               191       0.005236  \n",
       "37511           4               191       0.020942  \n",
       "37512           2               191       0.010471  \n",
       "37513           1               191       0.005236  \n",
       "37514           1               191       0.005236  \n",
       "37515           3               191       0.015707  \n",
       "37516           3               191       0.015707  \n",
       "37517           1               191       0.005236  \n",
       "37518           1               191       0.005236  \n",
       "\n",
       "[37519 rows x 5 columns]"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df_triplet"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "E:\\Anaconda3\\lib\\site-packages\\sklearn\\model_selection\\_split.py:2179: FutureWarning: From version 0.21, test_size will always complement train_size unless both are specified.\n",
      "  FutureWarning)\n"
     ]
    }
   ],
   "source": [
    "#划分数据集\n",
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "total_index=df_triplet.index #用index作为划分指标\n",
    "train_index,test_index=train_test_split(total_index,train_size=0.8,random_state=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Int64Index([ 7971, 31459, 14683, 10005, 10371, 29054, 24134, 34060, 14660,\n",
       "            19371,\n",
       "            ...\n",
       "            32230, 17089, 14650, 15430, 14935, 20757, 32103, 30403, 21243,\n",
       "             2732],\n",
       "           dtype='int64', length=30015)"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_index"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "df_triplet_train=df_triplet.iloc[train_index]\n",
    "df_triplet_test=df_triplet.iloc[test_index]\n",
    "\n",
    "df_triplet_train.to_csv(dpath+'triplet_dataset_sub_train.csv')\n",
    "df_triplet_test.to_csv(dpath+'triplet_dataset_sub_train.csv')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "number of Users: 787\n",
      "number of Items: 800\n"
     ]
    }
   ],
   "source": [
    "#建立倒排表\n",
    "users=list(df_triplet_train['user'].unique())\n",
    "items=list(df_triplet_train['song'].unique())\n",
    "n_users=len(users)\n",
    "n_items=len(items)\n",
    "\n",
    "print(\"number of Users: %d\" % n_users)\n",
    "print(\"number of Items: %d\" % n_items)\n",
    "\n",
    "user_items=defaultdict(set)\n",
    "item_users=defaultdict(set)\n",
    "\n",
    "user_item_scores=ss.dok_matrix((n_users,n_items)) #打分表矩阵\n",
    "\n",
    "users_index=dict()\n",
    "items_index=dict()\n",
    "for i,u in enumerate(users):\n",
    "     users_index[u]=i\n",
    "\n",
    "for i,j in enumerate(items):\n",
    "     items_index[j]=i\n",
    "\n",
    "n_records=df_triplet_train.shape[0]\n",
    "\n",
    "for i in range(n_records):\n",
    "    user_index_i=users_index[df_triplet_train.iloc[i]['user']]  #提取当前用户\n",
    "    item_index_i=items_index[df_triplet_train.iloc[i]['song']]  #提取当前音乐\n",
    "    \n",
    "    user_items[user_index_i].add(item_index_i)\n",
    "    item_users[item_index_i].add(user_index_i)\n",
    "    \n",
    "    score=df_triplet_train.iloc[i]['fraction_play']  #播放次数比例作为打分\n",
    "    user_item_scores[user_index_i,item_index_i]=score\n",
    "\n",
    "pk.dump(user_items,open(\"song_user_items.pkl\",'wb'))\n",
    "pk.dump(item_users,open(\"song_item_users.pkl\",'wb'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "sio.mmwrite(\"user_item_scores\",user_item_scores)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "#计算用户平均打分\n",
    "users_mu=np.zeros(n_users)\n",
    "\n",
    "for u in range(n_users):\n",
    "    n_user_items=0\n",
    "    r_acc=0.0\n",
    "    \n",
    "    for i in user_items[u]:\n",
    "        r_acc+=user_item_scores[u,i]\n",
    "        n_user_items+=1\n",
    "    users_mu[u]=r_acc/n_user_items\n",
    "\n",
    "pk.dump(users_mu,open(\"song_users_mu.pkl\",'wb'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "#计算相似度\n",
    "def user_similarity_playcount(uid1,uid2):\n",
    "    si={}\n",
    "    for item in user_items[uid1]:\n",
    "        if item in user_items[uid2]:\n",
    "            si[item]=1 #该物品有效\n",
    "    n=len(si)\n",
    "    if(n==0):\n",
    "        similarity=0.0\n",
    "        return similarity\n",
    "    s1=np.array([user_item_scores[uid1,item]-users_mu[uid1] for item in si])\n",
    "    \n",
    "    s2=np.array([user_item_scores[uid2,item]-users_mu[uid2] for item in si])\n",
    "    \n",
    "    similarity=1-ssd.cosine(s1,s2)\n",
    "    \n",
    "    if np.isnan(similarity):#s1或s2的模为0\n",
    "        similarity=0.0\n",
    "    return similarity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ui=0 \n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "E:\\Anaconda3\\lib\\site-packages\\scipy\\spatial\\distance.py:698: RuntimeWarning: invalid value encountered in double_scalars\n",
      "  dist = 1.0 - uv / np.sqrt(uu * vv)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ui=100 \n",
      "ui=200 \n",
      "ui=300 \n",
      "ui=400 \n",
      "ui=500 \n",
      "ui=600 \n",
      "ui=700 \n"
     ]
    }
   ],
   "source": [
    "users_similarity_matrix = np.matrix(np.zeros(shape=(n_users, n_users)), float)\n",
    "\n",
    "for ui in range(n_users):\n",
    "    users_similarity_matrix[ui,ui] = 1.0\n",
    "    \n",
    "    #打印进度条\n",
    "    if(ui % 100 == 0):\n",
    "        print (\"ui=%d \" % (ui))\n",
    "\n",
    "    for uj in range(ui+1,n_users):   \n",
    "        users_similarity_matrix[uj,ui] = user_similarity_playcount(ui, uj)\n",
    "        users_similarity_matrix[ui,uj] = users_similarity_matrix[uj,ui]\n",
    "\n",
    "pk.dump(users_similarity_matrix, open(\"song_users_similarity.pkl\", 'wb')) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "#可以用另一种方法计算相似度，也就是是否播放过\n",
    "def user_similarity_played(uid1,uid2):\n",
    "    s1=user_items[uid1]\n",
    "    s2=user_items[uid2]\n",
    "    \n",
    "    intersection=s1.intersection(s2)\n",
    "    \n",
    "    if len(intersection)!=0:\n",
    "        union=s1.union(s2)\n",
    "        similarity=float(len(intersection))/float(len(union)) #交集比并集\n",
    "    else:\n",
    "        similarity=0\n",
    "    \n",
    "    return similarity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ui=0 \n",
      "ui=100 \n",
      "ui=200 \n",
      "ui=300 \n",
      "ui=400 \n",
      "ui=500 \n",
      "ui=600 \n",
      "ui=700 \n"
     ]
    }
   ],
   "source": [
    "users_similarity_matrix2 = np.matrix(np.zeros(shape=(n_users, n_users)), float)\n",
    "\n",
    "for ui in range(n_users):\n",
    "    users_similarity_matrix[ui,ui] = 1.0\n",
    "    \n",
    "    #打印进度条\n",
    "    if(ui % 100 == 0):\n",
    "        print (\"ui=%d \" % (ui))\n",
    "\n",
    "    for uj in range(ui+1,n_users):   \n",
    "        users_similarity_matrix[uj,ui] = user_similarity_played(ui, uj)\n",
    "        users_similarity_matrix[ui,uj] = users_similarity_matrix[uj,ui]\n",
    "\n",
    "pk.dump(users_similarity_matrix, open(\"song_users_similarity2.pkl\", 'wb')) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [],
   "source": [
    "#再计算items之间相似度\n",
    "def item_similarity_playcount(iid1,iid2):\n",
    "    su={}\n",
    "    for user in item_users[iid1]:\n",
    "        if user in item_users[iid2]:\n",
    "            su[user]=1 #该物品有效\n",
    "    n=len(su)\n",
    "    if(n==0):\n",
    "        similarity=0.0\n",
    "        return similarity\n",
    "    s1=np.array([user_item_scores[user,iid1]-users_mu[user] for user in su])\n",
    "    \n",
    "    s2=np.array([user_item_scores[user,iid2]-users_mu[user] for user in su])\n",
    "    \n",
    "    similarity=1-ssd.cosine(s1,s2)\n",
    "    \n",
    "    if np.isnan(similarity):#s1或s2的模为0\n",
    "        similarity=0.0\n",
    "    return similarity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "#可以用另一种方法计算相似度，也就是是否播放过\n",
    "def items_similarity_played(iid1,iid2):\n",
    "    s1=user_items[iid1]\n",
    "    s2=user_items[iid2]\n",
    "    \n",
    "    intersection=s1.intersection(s2)\n",
    "    \n",
    "    if len(intersection)!=0:\n",
    "        union=s1.union(s2)\n",
    "        similarity=float(len(intersection))/float(len(union)) #交集比并集\n",
    "    else:\n",
    "        similarity=0\n",
    "    \n",
    "    return similarity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "i=0 \n",
      "i=100 \n",
      "i=200 \n",
      "i=300 \n",
      "i=400 \n",
      "i=500 \n",
      "i=600 \n",
      "i=700 \n"
     ]
    }
   ],
   "source": [
    "#计算items的相似性\n",
    "items_similarity_matrix = np.matrix(np.zeros(shape=(n_items, n_items)), float)\n",
    "\n",
    "for i in range(n_items):\n",
    "    items_similarity_matrix[i,i] = 1.0\n",
    "    \n",
    "    #打印进度条\n",
    "    if(i % 100 == 0):\n",
    "        print (\"i=%d \" % (i))\n",
    "\n",
    "    for j in range(i+1,n_items):   \n",
    "        items_similarity_matrix[j,i] = item_similarity_playcount(i,j)\n",
    "        items_similarity_matrix[i,j] = items_similarity_matrix[j,i]\n",
    "\n",
    "pk.dump(users_similarity_matrix, open(\"song_items_similarity.pkl\", 'wb')) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "i=0 \n",
      "i=100 \n",
      "i=200 \n",
      "i=300 \n",
      "i=400 \n",
      "i=500 \n",
      "i=600 \n",
      "i=700 \n"
     ]
    }
   ],
   "source": [
    "#计算items的相似性\n",
    "items_similarity_matrix2 = np.matrix(np.zeros(shape=(n_items, n_items)), float)\n",
    "\n",
    "for i in range(n_items):\n",
    "    items_similarity_matrix2[i,i] = 1.0\n",
    "    \n",
    "    #打印进度条\n",
    "    if(i % 100 == 0):\n",
    "        print (\"i=%d \" % (i))\n",
    "\n",
    "    for j in range(i+1,n_items):   \n",
    "        items_similarity_matrix[j,i] = items_similarity_played(i,j)\n",
    "        items_similarity_matrix[i,j] = items_similarity_matrix[j,i]\n",
    "\n",
    "pk.dump(users_similarity_matrix, open(\"song_items_similarity2.pkl\", 'wb')) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [],
   "source": [
    "#隐含变量的维数\n",
    "K = 40\n",
    "\n",
    "#item和用户的偏置项\n",
    "bi = np.zeros((n_items,1))    \n",
    "bu = np.zeros((n_users,1))   \n",
    "\n",
    "#item和用户的隐含向量\n",
    "qi =  np.zeros((n_items,K))    \n",
    "pu =  np.zeros((n_users,K))   \n",
    "\n",
    "\n",
    "for uid in range(n_users):  #对每个用户\n",
    "    pu[uid] = np.reshape(random((K,1))/10*(np.sqrt(K)),K)\n",
    "       \n",
    "for iid in range(n_items):  #对每个item\n",
    "    qi[iid] = np.reshape(random((K,1))/10*(np.sqrt(K)),K)\n",
    "\n",
    "#所有用户的平均打分\n",
    "mu = df_triplet['fraction_play'].mean()  #average rating"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [],
   "source": [
    "def svd_pred(uid, iid):  \n",
    "    score = mu + bi[iid] + bu[uid] + np.sum(qi[iid]* pu[uid])  \n",
    "        \n",
    "    #将打分范围控制在1-5之间\n",
    "    #if score>5:  \n",
    "        #score = 5  \n",
    "    #elif score<1:  \n",
    "        #score = 1  \n",
    "        \n",
    "    return score  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The 0-th  step is running\n",
      "the rmse of this step on train data is  [0.88776085]\n",
      "The 1-th  step is running\n",
      "the rmse of this step on train data is  [0.15363099]\n",
      "The 2-th  step is running\n",
      "the rmse of this step on train data is  [0.10536456]\n",
      "The 3-th  step is running\n",
      "the rmse of this step on train data is  [0.08878845]\n",
      "The 4-th  step is running\n",
      "the rmse of this step on train data is  [0.08044975]\n",
      "The 5-th  step is running\n",
      "the rmse of this step on train data is  [0.07489926]\n",
      "The 6-th  step is running\n",
      "the rmse of this step on train data is  [0.07108803]\n",
      "The 7-th  step is running\n",
      "the rmse of this step on train data is  [0.06814569]\n",
      "The 8-th  step is running\n",
      "the rmse of this step on train data is  [0.06580325]\n",
      "The 9-th  step is running\n",
      "the rmse of this step on train data is  [0.06398658]\n",
      "The 10-th  step is running\n",
      "the rmse of this step on train data is  [0.06244051]\n",
      "The 11-th  step is running\n",
      "the rmse of this step on train data is  [0.06124399]\n",
      "The 12-th  step is running\n",
      "the rmse of this step on train data is  [0.06028497]\n",
      "The 13-th  step is running\n",
      "the rmse of this step on train data is  [0.05945366]\n",
      "The 14-th  step is running\n",
      "the rmse of this step on train data is  [0.05872103]\n",
      "The 15-th  step is running\n",
      "the rmse of this step on train data is  [0.05817702]\n",
      "The 16-th  step is running\n",
      "the rmse of this step on train data is  [0.05765688]\n",
      "The 17-th  step is running\n",
      "the rmse of this step on train data is  [0.05724101]\n",
      "The 18-th  step is running\n",
      "the rmse of this step on train data is  [0.05688057]\n",
      "The 19-th  step is running\n",
      "the rmse of this step on train data is  [0.05656733]\n",
      "The 20-th  step is running\n",
      "the rmse of this step on train data is  [0.05627753]\n",
      "The 21-th  step is running\n",
      "the rmse of this step on train data is  [0.0560659]\n",
      "The 22-th  step is running\n",
      "the rmse of this step on train data is  [0.05584498]\n",
      "The 23-th  step is running\n",
      "the rmse of this step on train data is  [0.05564599]\n",
      "The 24-th  step is running\n",
      "the rmse of this step on train data is  [0.05548093]\n",
      "The 25-th  step is running\n",
      "the rmse of this step on train data is  [0.05533525]\n",
      "The 26-th  step is running\n",
      "the rmse of this step on train data is  [0.0552082]\n",
      "The 27-th  step is running\n",
      "the rmse of this step on train data is  [0.05509364]\n",
      "The 28-th  step is running\n",
      "the rmse of this step on train data is  [0.05497145]\n",
      "The 29-th  step is running\n",
      "the rmse of this step on train data is  [0.0548906]\n",
      "The 30-th  step is running\n",
      "the rmse of this step on train data is  [0.05480123]\n",
      "The 31-th  step is running\n",
      "the rmse of this step on train data is  [0.05472938]\n",
      "The 32-th  step is running\n",
      "the rmse of this step on train data is  [0.05464972]\n",
      "The 33-th  step is running\n",
      "the rmse of this step on train data is  [0.05458779]\n",
      "The 34-th  step is running\n",
      "the rmse of this step on train data is  [0.05452856]\n",
      "The 35-th  step is running\n",
      "the rmse of this step on train data is  [0.05447755]\n",
      "The 36-th  step is running\n",
      "the rmse of this step on train data is  [0.05442946]\n",
      "The 37-th  step is running\n",
      "the rmse of this step on train data is  [0.05438247]\n",
      "The 38-th  step is running\n",
      "the rmse of this step on train data is  [0.05434182]\n",
      "The 39-th  step is running\n",
      "the rmse of this step on train data is  [0.05430622]\n",
      "The 40-th  step is running\n",
      "the rmse of this step on train data is  [0.05427051]\n",
      "The 41-th  step is running\n",
      "the rmse of this step on train data is  [0.05423976]\n",
      "The 42-th  step is running\n",
      "the rmse of this step on train data is  [0.05421091]\n",
      "The 43-th  step is running\n",
      "the rmse of this step on train data is  [0.05418284]\n",
      "The 44-th  step is running\n",
      "the rmse of this step on train data is  [0.05415938]\n",
      "The 45-th  step is running\n",
      "the rmse of this step on train data is  [0.05413519]\n",
      "The 46-th  step is running\n",
      "the rmse of this step on train data is  [0.05411428]\n",
      "The 47-th  step is running\n",
      "the rmse of this step on train data is  [0.05409583]\n",
      "The 48-th  step is running\n",
      "the rmse of this step on train data is  [0.05407838]\n",
      "The 49-th  step is running\n",
      "the rmse of this step on train data is  [0.05406082]\n"
     ]
    }
   ],
   "source": [
    "#模型训练\n",
    "#gamma：为学习率\n",
    "#Lambda：正则参数\n",
    "#steps：迭代次数\n",
    "\n",
    "steps=50\n",
    "gamma=0.04\n",
    "Lambda=0.15\n",
    "\n",
    "#总的打分记录数目\n",
    "n_records = df_triplet_train.shape[0]\n",
    "\n",
    "for step in range(steps):  \n",
    "    print ('The ' + str(step) + '-th  step is running' )\n",
    "    rmse_sum=0.0 \n",
    "            \n",
    "    #将训练样本打散顺序\n",
    "    kk = np.random.permutation(n_records)  \n",
    "    for j in range(n_records):  \n",
    "        #每次一个训练样本\n",
    "        line = kk[j]  \n",
    "        \n",
    "        uid = users_index [df_triplet_train.iloc[line]['user']]\n",
    "        iid = items_index [df_triplet_train.iloc[line]['song']]\n",
    "    \n",
    "        rating  = df_triplet.iloc[line]['fraction_play']\n",
    "                \n",
    "        #预测残差\n",
    "        eui = rating - svd_pred(uid, iid)  \n",
    "        #残差平方和\n",
    "        rmse_sum += eui**2  \n",
    "                \n",
    "        #随机梯度下降，更新\n",
    "        bu[uid] += gamma * (eui - Lambda * bu[uid])  \n",
    "        bi[iid] += gamma * (eui - Lambda * bi[iid]) \n",
    "                \n",
    "        temp = qi[iid]  \n",
    "        qi[iid] += gamma * (eui* pu[uid]- Lambda*qi[iid] )  \n",
    "        pu[uid] += gamma * (eui* temp - Lambda*pu[uid])  \n",
    "            \n",
    "    #学习率递减\n",
    "    gamma=gamma*0.93  \n",
    "    print (\"the rmse of this step on train data is \",np.sqrt(rmse_sum/n_records))  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [],
   "source": [
    "# A method for saving object data to JSON file\n",
    "def save_json(filepath):\n",
    "    dict_ = {}\n",
    "    dict_['mu'] = mu\n",
    "    dict_['K'] = K\n",
    "    \n",
    "    dict_['bi'] = bi.tolist()\n",
    "    dict_['bu'] = bu.tolist()\n",
    "    \n",
    "    dict_['qi'] = qi.tolist()\n",
    "    dict_['pu'] = pu.tolist()\n",
    "\n",
    "    # Creat json and save to file\n",
    "    json_txt = json.dumps(dict_)\n",
    "    with open(filepath, 'w') as file:\n",
    "        file.write(json_txt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [],
   "source": [
    "# A method for loading data from JSON file\n",
    "def load_json(filepath):\n",
    "    with open(filepath, 'r') as file:\n",
    "        dict_ = json.load(file)\n",
    "\n",
    "        mu = dict_['mu']\n",
    "        K = dict_['K']\n",
    "\n",
    "        bi = np.asarray(dict_['bi'])\n",
    "        bu = np.asarray(dict_['bu'])\n",
    "    \n",
    "        qi = np.asarray(dict_['qi'])\n",
    "        pu = np.asarray(dict_['pu'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [],
   "source": [
    "import json\n",
    "save_json('svd_model.json')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [],
   "source": [
    "### 预测用户对item的打分 基于用户协同过滤\n",
    "def User_CF_pred(uid, iid): \n",
    "    sim_accumulate=0.0  \n",
    "    rat_acc=0.0 \n",
    "    for user_id in item_users[iid]:  #对item iid打过分的所有用户\n",
    "        #计算当前用户与给item i打过分的用户之间的相似度\n",
    "        #sim = user_similarity(user_id, uid)\n",
    "        sim = users_similarity_matrix[user_id,uid]\n",
    "            \n",
    "        if sim != 0: \n",
    "            rat_acc += sim * (user_item_scores[user_id,iid] - users_mu[user_id])   #用户user对item i的打分\n",
    "            sim_accumulate += np.abs(sim)  \n",
    "        \n",
    "    if sim_accumulate != 0:  \n",
    "        score = users_mu[uid] + rat_acc/sim_accumulate\n",
    "    else: #no similar users,return average rates of the user \n",
    "        score = users_mu[uid]\n",
    "    \n",
    "    return score"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [],
   "source": [
    "###基于物品的协同过滤\n",
    "### 预测用户对item的打分, 取该用户n_Knns最相似的物品\n",
    "def Item_CF_pred2(uid, iid, n_Knns): \n",
    "    sim_accumulate=0.0  \n",
    "    rat_acc=0.0 \n",
    "    n_nn_items = 0\n",
    "    \n",
    "    #相似度排序\n",
    "    cur_items_similarity = np.array(items_similarity_matrix[iid,:])\n",
    "    cur_items_similarity = cur_items_similarity.flatten()  #把某个物品的相似度一维化才能进行排序\n",
    "    sort_index = sorted(((e,i) for i,e in enumerate(list(cur_items_similarity))), reverse=True)\n",
    "    \n",
    "    sort_index\n",
    "    for i in range(0,len(sort_index)):\n",
    "        cur_item_index = sort_index[i][1]\n",
    "        \n",
    "        if n_nn_items >= n_Knns:  #相似的items已经足够多（>n_Knns）\n",
    "            break;\n",
    "        \n",
    "        if cur_item_index in user_items[uid]: #对用户打过分的item\n",
    "           #计算当前用户打过分item与其他item之间的相似度\n",
    "            #sim = item_similarity(cur_item_index, iid)\n",
    "            sim = items_similarity_matrix[iid, cur_item_index]\n",
    "            \n",
    "            if sim != 0: \n",
    "                rat_acc += sim * (user_item_scores[uid, cur_item_index])   #用户user对item i的打分\n",
    "                sim_accumulate += np.abs(sim)  \n",
    "        \n",
    "            n_nn_items += 1\n",
    "        \n",
    "    if sim_accumulate != 0:  \n",
    "        score = rat_acc/sim_accumulate\n",
    "    else:   #no similar items,return average rates of the user   \n",
    "        score = users_mu[uid]\n",
    "    \n",
    "    if score <0:\n",
    "        score = 0.0\n",
    "    \n",
    "    return score"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [],
   "source": [
    "def svd_pred(uid, iid):  \n",
    "    score = mu + bi[iid] + bu[uid] + np.sum(qi[iid]* pu[uid])  \n",
    "        \n",
    "    #将打分范围控制在1-5之间\n",
    "    #if score>5:  \n",
    "        #score = 5  \n",
    "    #elif score<1:  \n",
    "        #score = 1  \n",
    "        \n",
    "    return score  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [],
   "source": [
    "#user：用户\n",
    "N_KNNS=10\n",
    "#返回推荐items及其打分（DataFrame）\n",
    "def recommend(user):\n",
    "    cur_user_id = users_index[user]\n",
    "    \n",
    "    #训练集中该用户打过分的item\n",
    "    cur_user_items = user_items[cur_user_id]\n",
    "\n",
    "    #该用户对所有item的打分\n",
    "    user_items_scores = np.zeros(n_items)\n",
    "\n",
    "    #预测打分\n",
    "    for i in range(n_items):  # all items \n",
    "        if i not in cur_user_items: #训练集中没打过分\n",
    "            user_items_scores[i] = User_CF_pred(cur_user_id, i)  #预测打分\n",
    "    \n",
    "    #推荐\n",
    "    #Sort the indices of user_item_scores based upon their value，Also maintain the corresponding score\n",
    "    sort_index = sorted(((e,i) for i,e in enumerate(list(user_items_scores))), reverse=True)\n",
    "    \n",
    "    #Create a dataframe from the following\n",
    "    columns = ['item_id', 'score']\n",
    "    df = pd.DataFrame(columns=columns)\n",
    "         \n",
    "    #Fill the dataframe with top 20 (n_rec_items) item based recommendations\n",
    "    #sort_index = sort_index[0:n_rec_items]\n",
    "    #Fill the dataframe with all items based recommendations\n",
    "    for i in range(0,len(sort_index)):\n",
    "        cur_item_index = sort_index[i][1] \n",
    "        cur_item = list (items_index.keys()) [list (items_index.values()).index (cur_item_index)]\n",
    "            \n",
    "        if ~np.isnan(sort_index[i][0]) and cur_item_index not in cur_user_items:\n",
    "            df.loc[len(df)]=[cur_item, sort_index[i][0]]\n",
    "    \n",
    "    return df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "67c5b5b1982902d15badd8ce0c18b3278ec4bfc0 is a new user.\n",
      "\n",
      "62420be0fd0df5ab0eb4cba35a4bc7cb3e3b506a is a new user.\n",
      "\n",
      "3ab78e39bddeaeb789edad041fff03050077417c is a new user.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "#统计总的用户\n",
    "unique_users_test = df_triplet_test['user'].unique()\n",
    "\n",
    "#为每个用户推荐的item的数目\n",
    "n_rec_items = 20\n",
    "\n",
    "#性能评价参数初始化，用户计算Percison和Recall\n",
    "n_hits = 0\n",
    "n_total_rec_items = 0\n",
    "n_test_items = 0\n",
    "\n",
    "#所有被推荐商品的集合（对不同用户），用于计算覆盖度\n",
    "all_rec_items = set()\n",
    "\n",
    "#残差平方和，用与计算RMSE\n",
    "rss_test = 0.0\n",
    "\n",
    "#对每个测试用户\n",
    "for user in unique_users_test:\n",
    "    #测试集中该用户打过分的电影（用于计算评价指标的真实值）\n",
    "    if user not in users_index:   #user在训练集中没有出现过，新用户不能用协同过滤\n",
    "        print(str(user) + ' is a new user.\\n')\n",
    "        continue\n",
    "   \n",
    "    user_records_test= df_triplet_test[df_triplet_test.user == user]   #提取当前user的信息\n",
    "    \n",
    "    #对每个测试用户，计算该用户对训练集中未出现过的商品的打分，并基于该打分进行推荐（top n_rec_items）\n",
    "    #返回结果为DataFrame\n",
    "    rec_items = recommend(user)\n",
    "    \n",
    "    for i in range(n_rec_items):\n",
    "        item = rec_items.iloc[i]['item_id']\n",
    "        \n",
    "        if item in user_records_test['song'].values:\n",
    "            n_hits += 1                                      #如果推荐的商品在test集里面就认为hit\n",
    "        all_rec_items.add(item)                               #这里只是单纯的记录前十推荐的商品\n",
    "    \n",
    "    #计算rmse\n",
    "    for i in range(user_records_test.shape[0]):                           #遍历当前用户的每一个item核打分，在测试集上，并在训练集上找到他\n",
    "        item = user_records_test.iloc[i]['song']\n",
    "        score = user_records_test.iloc[i]['fraction_play']\n",
    "        \n",
    "        df1 = rec_items[rec_items.item_id == item]\n",
    "        if(df1.shape[0] == 0): #item在训练集中没有出现过，新item不能被协同过滤推荐\n",
    "            print(str(item) + ' is a new item.\\n')\n",
    "            continue\n",
    "        pred_score = df1['score'].values[0]\n",
    "        rss_test += (pred_score - score)**2     #残差平方和\n",
    "    \n",
    "    #推荐的item总数\n",
    "    n_total_rec_items += n_rec_items\n",
    "    \n",
    "    #真实item的总数\n",
    "    n_test_items += user_records_test.shape[0]\n",
    "\n",
    "#Precision & Recall\n",
    "precision = n_hits / (1.0*n_total_rec_items)    #命中/所有推荐的\n",
    "recall = n_hits / (1.0*n_test_items)            #命中/所有被顾客喜欢的\n",
    "\n",
    "#覆盖度：推荐商品占总需要推荐商品的比例\n",
    "coverage = len(all_rec_items) / (1.0* n_items)\n",
    "\n",
    "#打分的均方误差\n",
    "rmse=np.sqrt(rss_test / df_triplet_test.shape[0]) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.01396957123098202"
      ]
     },
     "execution_count": 66,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "precision"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.026929742700973203"
      ]
     },
     "execution_count": 67,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "recall"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.39375"
      ]
     },
     "execution_count": 68,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "coverage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
